
/*========================================================================================
 *                                                                                      *
 *               Copyright(c) 2013-2014, Cha SangWoo, All rights reserved.              *
 *                                                                                      *
 * This file is part of ChaOS.                                                          *
 *                                                                                      *
 * Permission to use, copy, modify, and distribute this software in source and binary   *
 * forms and its documentation for any purpose and without fee is hereby granted,       *
 * provided that the above copyright notice appear in all copies and that both that     *
 * copyright notice and this permission notice appear in supporting documentation.      *
 *                                                                                      *
 * THIS SOFTWARE IS PROVIDED BY THE CHA SANGWOO AND CONTRIBUTORS "AS IS" AND ANY        *
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED            *
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.   *
 * IN NO EVENT SHALL CHA SANGWOO OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,    *
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT         *
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,          *
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF            *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE      *
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,                    *
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                   *
 *                                                                                      *
========================================================================================*/

#ifndef __CO_KE_CORE_H__
#define __CO_KE_CORE_H__

#include "co_port.h"
#include "co_types.h"
#include "co_log.h"
#include "co_heap.h"

#ifdef __cplusplus
    extern "C" {
    namespace ChaOS {
#endif

//////////////////////////////////////  < BEGIN >  ///////////////////////////////////////

/*======================================================================================*/
/*
    Macro functions
*/
/*======================================================================================*/

#define OFFSET_OF(TYPE, MEMBER)             ((int)&(((TYPE*)0)->MEMBER))

#define CASTING_OF(TYPE, MEMBER, ADDRESS)   ((TYPE*)(((char*)ADDRESS) - OFFSET_OF(TYPE, MEMBER)))

// It make a size aligned by boundary
#define SIZE_ALIGN(SIZE, BOUNDARY)    (((SIZE)+((BOUNDARY)-1)) & ~((BOUNDARY)-1))

// get minimum or maximum value
#define CO_MAX(X,Y)     (((UINT)(X)>(UINT)(Y))?(X):(Y))
#define CO_MIN(X,Y)     (((UINT)(X)>(UINT)(Y))?(Y):(X))

// get current thread
#define GET_CURRENT_THREAD()        ((THREAD_CB*)_gp_cur_thread)

#define STOP_PROCESS()                                                                   \
        {                                                                                \
            _co_log_printf("STOP_API", "!!!!!  STOP at [%s] !!!!!", __FUNCTION__);       \
            _co_log_printf("STOP_API", "!!!!!  STOP at [%s] !!!!!", __FUNCTION__);       \
            while(1);                                                                    \
        }


/*======================================================================================*/
/*
    definition
*/
/*======================================================================================*/

#define CO_THREAD_READY         (1 <<  0)
#define CO_THREAD_RUNNING       (1 <<  2)
#define CO_THREAD_WAIT_TIME     (1 <<  3)
#define CO_THREAD_WAIT_OBJECT   (1 <<  4)

#define CO_TIMER_STOP           (0)
#define CO_TIMER_START          (1 <<  0)
#define CO_TIMER_REPEATE        (1 <<  4)

#define CO_NESTED_COUNT_BASE        (0)
#define CO_NESTED_COUNT_USER        (CO_NESTED_COUNT_BASE+1)

#define CO_ENTER_CRITICAL()         (PORT_INT_DISABLE())
#define CO_LEAVE_CRITICAL()         (PORT_INT_ENABLE())

/*======================================================================================*/
/*
    Check Object ID definition
*/
/*======================================================================================*/
#if (FLAG_USE_CHECK_OBJECT_ID == CO_ENABLE)

    typedef enum
    {
        OBJID_THREAD      = 0x00001000,
        OBJID_SEMAPHORE   = 0x00002000,
        OBJID_MUTEX       = 0x00003000,
        OBJID_QUEUE       = 0x00004000,
        OBJID_TIMER       = 0x00005000,
        OBJID_STATE       = 0x00006000,
        OBJID_STATE_TIMER = 0x00007000,
        OBJID_BYTE_POOL   = 0x00008000,
        OBJID_POOL_BLOCK  = 0x00009000,
        OBJID_RING_BUFFER = 0x0000A000,
        OBJID_DRVIER      = 0x0000B000,
        OBJID_MAX

    } _OBJECT_IDS_;

    #define OBJID_MAGIC_NUMBER      (344)
    #define OBJ_THREAD_ID           (OBJID_MAGIC_NUMBER + OBJID_THREAD)
    #define OBJ_MUTEX_ID            (OBJID_MAGIC_NUMBER + OBJID_MUTEX)
    #define OBJ_SEMAPHORE_ID        (OBJID_MAGIC_NUMBER + OBJID_SEMAPHORE)
    #define OBJ_QUEUE_ID            (OBJID_MAGIC_NUMBER + OBJID_QUEUE)
    #define OBJ_TIMER_ID            (OBJID_MAGIC_NUMBER + OBJID_TIMER)
    #define OBJ_STATE_ID            (OBJID_MAGIC_NUMBER + OBJID_STATE)
    #define OBJ_STATE_TIMER_ID      (OBJID_MAGIC_NUMBER + OBJID_STATE_TIMER)
    #define OBJ_BYTE_POOL_ID        (OBJID_MAGIC_NUMBER + OBJID_BYTE_POOL)
    #define OBJ_POOL_BLOCK_ID       (OBJID_MAGIC_NUMBER + OBJID_POOL_BLOCK)
    #define OBJ_RING_BUFFER_ID      (OBJID_MAGIC_NUMBER + OBJID_RING_BUFFER)
    #define OBJ_DRIVER_ID           (OBJID_MAGIC_NUMBER + OBJID_DRVIER)

    #define OBJID_DEFINE            UINT    objID;
    #define OBJID_SET(OBJ,ID)       ((OBJ)->objID = (UINT)ID)
    #define OBJID_CHECK(OBJ,ID)     CO_ASSERT((OBJ)->objID == (UINT)(ID))

#else  // (FLAG_USE_CHECK_OBJECT_ID != CO_ENABLE)

    #define OBJID_DEFINE            
    #define OBJID_SET(OBJ,ID)       DO_NOTHING
    #define OBJID_CHECK(OBJ,ID)     DO_NOTHING

#endif // (FLAG_USE_CHECK_OBJECT_ID == CO_ENABLE)


/*======================================================================================*/
/*
    Linked List Macro for THREAD_CB
*/
/*======================================================================================*/

#define CO_THREAD_INIT(pthread)                                                          \
        {                                                                                \
            (pthread)->pnext = (struct THREAD_CB_T*)(pthread);                           \
            (pthread)->pprev = (struct THREAD_CB_T*)(pthread);                           \
        }

#define CO_THREAD_IS_USED(pthread)                                                       \
        (                                                                                \
            ((pthread)->pnext != (struct THREAD_CB_T*)(pthread))                         \
        )

#define CO_THREAD_IS_ALONE(pthread)                                                      \
        (                                                                                \
            ((pthread)->pnext == (struct THREAD_CB_T*)(pthread))                         \
        )

#define CO_THREAD_ADD_PREV(pspot, pthread)                                               \
        {                                                                                \
            (pthread)->pnext = (struct THREAD_CB_T*)(pspot);                             \
            (pspot)->pprev->pnext = (struct THREAD_CB_T*)(pthread);                      \
                                                                                         \
            (pthread)->pprev = (pspot)->pprev;                                           \
            (pspot)->pprev = (struct THREAD_CB_T*)(pthread);                             \
        }

#define CO_THREAD_CUT(pthread)                                                           \
        {                                                                                \
            (pthread)->pprev->pnext = (pthread)->pnext;                                  \
            (pthread)->pnext->pprev = (pthread)->pprev;                                  \
                                                                                         \
            (pthread)->pnext = (struct THREAD_CB_T*)(pthread);                           \
            (pthread)->pprev = (struct THREAD_CB_T*)(pthread);                           \
        }


/*======================================================================================*/
/*!
    @brief  Information to control the heap memory.
*/
/*======================================================================================*/
typedef struct
{
    UINT8              *pcur;              // current address of memory
    UINT8              *pmax;              // end     address of memory  

    UINT8               heap[CO_HEAP_SIZE];

} HEAP_CB;


/*======================================================================================*/
/*
    @brief  Information to control the thread.
*/
/*======================================================================================*/
typedef struct THREAD_CB_T
{
    UINT                  stack_point;          // fixed position

#if (FLAG_USE_THREAD_NAME == CO_ENABLE)
    CHAR                  name[NAME_LENGTH];    // name of thread
#endif

    struct THREAD_CB_T   *pnext;                // next thread point in list
    struct THREAD_CB_T   *pprev;                // previous thread point in list

    UINT8                 state;                // thread state
    UINT8                 result;               // result of waiting
    UINT16                wait_time;            // waiting time
    OBJECT                wait_object;          // waiting object

    OBJID_DEFINE

    USER_TRACE_STACK_EXTENTION

    USER_THREAD_EXTENTION

} THREAD_CB;


/*======================================================================================*/
/*
    @brief  Information to control the semaphore.
*/
/*======================================================================================*/
typedef struct
{
    OBJID_DEFINE

    UINT16                cur_count;
    UINT16                max_count;

} SEMAPHORE_CB;


/*======================================================================================*/
/*
    @brief  Information to control the mutex.
*/
/*======================================================================================*/
#if (FLAG_USE_CHAOS_MUTEX == CO_ENABLE)

    typedef struct
    {
        OBJID_DEFINE

        THREAD_CB        *powner;

    } MUTEX_CB;

#endif


/*======================================================================================*/
/*
    @brief  Information to control the queue.
*/
/*======================================================================================*/
#if (FLAG_USE_CHAOS_QUEUE == CO_ENABLE)

    typedef struct
    {
        OBJID_DEFINE

        OBJECT          objRecv;
        OBJECT          objSend;

        UINT16          item_size;
        UINT16          item_count;
        UINT16          read_pos;
        UINT16          write_pos;
        UINT16          max_size;
        UINT16          reserved;

        UINT32          start[1];

    } QUEUE_CB;

#endif

/*======================================================================================*/
/*
    @brief  Information to control the state engine.
*/
/*======================================================================================*/
#if (FLAG_USE_CHAOS_STATE_ENGINE == CO_ENABLE)

    typedef struct
    {
        UINT32      Command;
        VOID*       pData;
    
    } STATE_MSG;

    typedef struct
    {
        OBJID_DEFINE

#if (FLAG_USE_CHAOS_STATE_ENGINE_NAME == CO_ENABLE)
        CHAR                  name[NAME_LENGTH];    // name of thread
#endif

        OBJECT          objQueue;

        STATE           cur_state;
        VOID           *puser_data;

        UINT8           call_count;
        UINT8           stack_pos;
        UINT16          reserved;

        STATE           stack[SIZE_CHAOS_STATE_ENGINE_STACK];

        STATE_MSG       message;

    } STATE_ENGINE_CB;

    typedef struct
    {
        OBJID_DEFINE

        STATE_ENGINE_CB    *pstate;
        OBJECT              timer;

    } STATE_ENGINE_TIMER_CB;

#endif

/*======================================================================================*/
/*
    @brief  Information to control the software timer
*/
/*======================================================================================*/
#if (FLAG_USE_CHAOS_SW_TIMER == CO_ENABLE)

    typedef struct TIMER_CB_T
    {
        OBJID_DEFINE

        struct TIMER_CB_T      *pnext;          // next control block for timer

        UINT16                  state;
        UINT16                  id;             // id number specified by user

        UINT16                  repeat_time;    // if repeat is enable, value is same with wait_time
        UINT16                  wait_time;      // waiting time

        TIMER_PROC              proc;           // entry point of timer
        VOID                   *parg;           // argument specified by user

    } TIMER_CB;

#endif

/*======================================================================================*/
/*
    @brief  Information to control the software timer
*/
/*======================================================================================*/
#if (FLAG_USE_CHAOS_BYTE_POOL == CO_ENABLE)

    typedef struct POOL_BLOCK_CB_T
    {
        OBJID_DEFINE

        struct POOL_BLOCK_CB_T     *pnext;
        OBJECT                      objPool;

        UINT32                      data[1];

    } POOL_BLOCK_CB;


    typedef struct
    {
        OBJID_DEFINE

        struct POOL_BLOCK_CB_T     *pfree;

    } BYTE_POOL_CB;

#endif

/*======================================================================================*/
/*
    @brief  Information to control the ring buffer
*/
/*======================================================================================*/
#if (FLAG_USE_CHAOS_RING_BUFFER == CO_ENABLE)

    typedef struct
    {
        OBJID_DEFINE

        UINT16          read_pos;
        UINT16          write_pos;

        UINT32          max_count;
        OBJECT          objGetCount;
        OBJECT          objPutCount;

        UINT8           data[4];

    } RING_BUFFER_CB;

#endif

/*======================================================================================*/
/*
     ChaOS Global Variables
*/
/*======================================================================================*/

#ifdef __CO_GLOBALS__
    #define CO_GLOBAL
#else
    #define CO_GLOBAL   extern
#endif

CO_GLOBAL volatile      THREAD_CB      *_gp_cur_thread;     // current thread CB
CO_GLOBAL volatile      UINT8           _g_nested_count;
CO_GLOBAL volatile      UINT32          _g_system_tick;     // system tick

CO_GLOBAL               THREAD_CB      *_gp_idle_thread;
CO_GLOBAL               THREAD_CB      *_gp_block_list;
CO_GLOBAL               THREAD_CB      *_gp_ready_list;

#if (FLAG_USE_CHAOS_SW_TIMER == CO_ENABLE)
CO_GLOBAL               TIMER_CB       *_gp_timer_list;
#endif

CO_GLOBAL               HEAP_CB         _gst_heap_info;     // heap information


/*======================================================================================*/
/*
    @fn             VOID _core_update_system_tick(VOID)

    @brief          

    @return         None.
*/
/*======================================================================================*/
VOID _core_update_system_tick(VOID);


/*======================================================================================*/
/*
    @fn             VOID co_chaos_start(VOID)

    @brief          

    @return         None.
*/
/*======================================================================================*/
VOID _core_schedule_thread(VOID);


/*======================================================================================*/
/*
    @fn             VOID co_chaos_start(VOID)

    @brief          

    @return         None.
*/
/*======================================================================================*/
VOID _core_add_ready_list(THREAD_CB *pthread);


/*======================================================================================*/
/*
    @fn             VOID co_chaos_start(VOID)

    @brief          

    @return         None.
*/
/*======================================================================================*/
VOID _core_add_block_list(THREAD_CB *pthread);


/*======================================================================================*/
/*
    @fn             VOID co_chaos_start(VOID)

    @brief          

    @return         None.
*/
/*======================================================================================*/
THREAD_CB* _core_search_thread_in_block_list(OBJECT object);


/*======================================================================================*/
/*
    @fn             INT _idle_proc_(UINT arg)

    @brief          

    @return         
*/
/*======================================================================================*/
INT _idle_proc_(UINT arg);


/*======================================================================================*/
/*
    @fn             VOID _port_chaos_init(VOID)

    @brief          Prepare to start ChaOS.

    @return         None.
*/
/*======================================================================================*/
VOID _port_chaos_init(VOID);


/*======================================================================================*/
/*
    @fn             VOID _port_chaos_init(VOID)

    @brief          Start ChaOS.

    @return         None.
*/
/*======================================================================================*/
VOID _port_chaos_start(VOID);

/*======================================================================================*/
/*
    @fn             VOID _port_check_thread_stack(THREAD_CB *pthread)

    @brief          

    @return         None.
*/
/*======================================================================================*/
#if (FLAG_USE_STACK_TRACE == CO_ENABLE)
    VOID _port_check_thread_stack(THREAD_CB *pthread);
#endif

/*======================================================================================*/
/*
    @fn             UINT _port_log_printf(CHAR *pclass, const CHAR *pformat, ...)

    @brief          

    @param [in]     pbuffer - 
    @param [in]     size - 

    @return         None.
*/
/*======================================================================================*/
extern UINT _port_log_printf(CHAR *pclass, const CHAR *pformat, ...);


/*======================================================================================*/
/*
    @fn             VOID _port_thread_setup_stack(THREAD_CB    *pthread,
                                                  THREAD_PROC   entry_point,
                                                  UINT          argument,
                                                  UINT          stack_size)

    @brief          Setup stack of new thread

    @param [in]     pthread     - 
    @param [in]     entry_point - 
    @param [in]     argument    - 
    @param [in]     stack_size  - 

    @return         None.
*/
/*======================================================================================*/
VOID _port_thread_setup_stack(THREAD_CB    *pthread,
                              THREAD_PROC   entry_point,
                              UINT          argument,
                              UINT          stack_size);


//////////////////////////////////////  <  END  >  ///////////////////////////////////////

#ifdef __cplusplus
    } /* namespace ChaOS */
    } /* extern "C" */
#endif

#endif //__CO_KE_CORE_H__

